
//node库
const { promisify } = require('util')
const path = require('path')
const fs = require('fs')
//第三方库
const axios = require('axios');
let csvtojson = require('csvtojson');
const iconv = require('iconv-lite');
let xlsx = require('node-xlsx');
const open = require('open')
const { program } = require('commander')
const download = promisify(require('download-git-repo'))
//本地模块
const { commandSpawn } = require('../utils/terminal')
const { compile,wiriteToFile,getConfigContent,setConfigContent,getFiles,compileJava,getPageConfigFromPropsConfig,getDateTimeString,arr2Excel } = require('../utils/utils')

const createProjectAction = async (project) => {
    //1.读取配置文件的内容
    let filevueRepo = getConfigContent('repourl')
    if(!filevueRepo){
        console.log("请先在lib/config/repourl中配置vueRepo")
        return
    }
    //2.clone项目，使用了download-git-repo库
    await download(filevueRepo, project, { clone: true })//会在执行ztzq的文件下创建一个￥{project}的文件
    //3.执行npm install
    await commandSpawn(process.platform === "win32" ? "npm.cmd" : "npm", ['install'], { cwd: `./${project}` })
    //4.运行 npm run dev(这里不要用await，因为会阻塞后边的执行)
    commandSpawn(process.platform === "win32" ? "npm.cmd" : "npm", ['run', 'dev'], { cwd: `./${project}` })
    //5.打开浏览器
    //open("http://localhost:5174")
}


//添加页面的action
const addPageAndRouterAction = async (apipart, dest,pageName='未命名页面') => {
    //1.通过name拿到java的entity文件
    const folderPath = getConfigContent('platformpath'); // 将'./folder'替换为你想要读取的文件夹路径
    // 调用readdirSync函数同步地读取指定文件夹内容
    try {
        //1.拿到本项目所有文件
        const files = getFiles(folderPath);
        let simpleApiPart = apipart.replace(/[\_-]+/g,'')
        //2.拿到这个name对应的entity类，首先拿到本项目所有的entity文件（更细致的应该是先查controller文件，然后逐步在controller文件中查找ENTITY）
        const entityFiles = files.filter((file) => file.toLowerCase().endsWith(`\\${simpleApiPart.toLowerCase()}.java`));
        if(entityFiles.length==0){
            console.err("未找到对应的java文件，请检查！")
            return;
        }
        if(entityFiles.length>1){
            console.err("匹配到多个java文件，请检查！")
            return;
        }
        let targetEntityJavaFilePath = entityFiles[0];
        const targetEntityJavaContent = await fs.promises.readFile(targetEntityJavaFilePath,{encoding: 'utf8'})
        //3.拿到这个Entity继承的父类的文件路径(暂不处理BaseEntity)
        // let targetEntityExtendsJavaFilePath = ''
        // let targetEntityExtendsJavaContent = ''
        // let elements = targetEntityJavaContent.match(/^\s*public\s*class[\d\D]+\{\s$/gm)?.[0]?.split(/\s+/)//找到这一行：public class Handleprocess extends BaseEntity { 并且按空格分割
        // if(elements.length>0){//elements：["public","class","Handleprocess","extends","BaseEntity","{"]
        //     let extendsIndex = elements.indexOf('extends')
        //     if(extendsIndex>-1){
        //         let baseEntityName = elements[extendsIndex+1]
        //         const baseEntityFiles = files.filter((file) => file.toLowerCase().endsWith(`\\${baseEntityName.toLowerCase()}.java`));
        //         if(baseEntityFiles.length>0){
        //             let baseEntityFile = baseEntityFiles[0]
        //             targetEntityExtendsJavaFilePath = baseEntityFile
        //             targetEntityExtendsJavaContent = await fs.promises.readFile(targetEntityExtendsJavaFilePath,{encoding: 'utf8'})
        //         }
        //     }
        // }
        //4.解析java文件获取所有的字段名，字段类型
        const propsArray_entity = compileJava(targetEntityJavaContent) 
        //const propsArray_baseEntity = compileJava(targetEntityExtendsJavaContent) 

        //5.相同字段的话，父类字段代替子类字段
        let propsResult = [...propsArray_entity]
        // propsArray_baseEntity.forEach(item=>{//遍历BaseEntity，如果父组件已经有了，那么不添加
        //     if(!propsResult.find(el=>el.prop==item.prop)){
        //         propsResult.push(item)
        //     }
        // })
        //6.拿到了字段的配置后，获得页面的配置
        const pageConfig = getPageConfigFromPropsConfig(apipart,propsResult,pageName)
        //7.获取目标路径
         const targetDest = path.resolve(dest, apipart.replace(/[\_-]+/g,'').toLowerCase());
        // //8.渲染模板
        const pageResult = await compile('vue-component.ejs',pageConfig);
        const targetPagePath = path.resolve(targetDest, `index.vue`);
        wiriteToFile(targetPagePath,pageResult)
        //9.修改路由
        const route = `
            {
                path: '/${simpleApiPart}',
                name: '${simpleApiPart}',
                component: () => import('@/views/${simpleApiPart}/index.vue'),
            }
        `
        let routerContent = fs.readFileSync('src/router/index.js',{encoding:'utf8'})
        let finalRouterContent = routerContent.replace(/\{\s*(path|name|component)[\S\s]+?}\s*,*\s*(?=\])/mg,(origin)=>{
            if(origin.trim().endsWith(",")){
                return origin+route
            }else{
                return origin+","+route
            }
        })
        wiriteToFile('src/router/index.js',finalRouterContent)
        //10修改菜单
        let configContent = fs.readFileSync('public/config.js',{encoding:'utf8'})
        
        let menu = ''
        try{
            let strArray = configContent.match(/(?<=.*menu.*=\s*)\[[\s\S]*?}[\s,]*]\s*?,*\s*?(?=[\w\/])/g)
            let arr = []
            eval('arr = '+strArray)
            let targetObject = arr.pop()
            targetObject.children = []
            targetObject.name = pageName
            targetObject.path = simpleApiPart
            menu = JSON.stringify(targetObject)
        }catch(e){
            menu = null
            console.log("取config.js的菜单配置时出现错误"+e.message+'使用默认配置字段！')
        }
        if(!menu){
            menu = `{
                path: '${simpleApiPart}',
                name: '${pageName}',
                icon: 'Index',
                children:[]
            }`
        }
        //let finalMenuContent = configContent.replace(/^window\.[\D\d]{1,9}menu[\S\s]*?\}\s*,*(?=\s*\])$/mg,(origin)=>{
        let finalMenuContent = configContent.replace(/.*menu.*=\s*\[[\s\S]*?}(?=[\s,]*]\s*?,*\s*?[\w\/])/g,(p0)=>{
            return `${p0},
            ${menu}`
        })
        wiriteToFile('public/config.js',finalMenuContent)
    } catch (err) {
        console.error(`新增页面时出错:`, err);
    }
}
//设置后台路径
const setPlatFormPathAction = (fullpath) => {
    setConfigContent('platformpath',fullpath)
}
//转化service-def.json为apifox.json
const serviceDefToApifoxJson = async (filename,otherParmas)=>{
    let token = "1234567890"
    let dirName = "看板"+getDateTimeString()
    let parentId = 0

    console.log("otherParmas",otherParmas)
    otherParmas.forEach(element => {
        if(element.startsWith('token:')){
            token = element.substring(element.indexOf(':')+1)
        }
        if(element.startsWith('dirName:')){
            dirName = element.substring(element.indexOf(':')+1)
        }
        if(element.startsWith('parentId:')){
            parentId = element.substring(element.indexOf(':')+1)
        }
    });
    //1.读取文件
    let serviceDefContent = fs.readFileSync(filename,{encoding:'utf8'})
    //2.获取关键数据
    let serviceDefList= JSON.parse(serviceDefContent)
    serviceDefList.forEach(item=>{
        item.serviceCode = item.serviceCode || item['服务代码']
        item.serviceName = item.serviceName || item['服务名称']
        item.appName = item.appName || item['应用系统']
        item.serviceType = item.serviceType || item['服务类型']
        item.serviceTarget = item.serviceTarget || item['服务接口']
        item.serviceMethod = item.serviceMethod || item['服务方法']
        item.serviceParams = item.serviceParams || item['服务参数']
        item.serviceMark = item.serviceMark || item['服务标识']
        item.inureDate = item.inureDate || item['生效时间']
        item.expireDate = item.expireDate || item['失效时间']
        item.note = item.note || item['备注']
        item.helpDoc = item.helpDoc || item['帮助文档']
        item.requestBody = _getRequestBodyStr(item)
    })

    let data = {
        serviceDefList,
        token,
        dirName,
        parentId,
    }
    //3.转化apifoxData
    const apifoxData = await compile('apifox-service-array.ejs',data);
    //4.生成一个文件存储这个json
    wiriteToFile(`${filename.substring(0,filename.lastIndexOf('.'))}-apifox.json`,apifoxData)

    //以下是该方法用到的子方法
    function _getRequestBodyStr(serviceDef){
        let target= {params:{}}
        let serviceTarget = serviceDef.serviceTarget//com.shine.bms.facade.UserService
        let serviceMethod = serviceDef.serviceMethod//queryUserPermissions
        let serviceParams = serviceDef.serviceParams//userCode|java.lang.String; appName|java.lang.String; resourceType|java.lang.String
    
        let obj = {}
        if(serviceParams&&serviceParams!='无'){
            let params = serviceParams.split(";")
            console.log(params)
            let paramStr = ""
            for(let i=0;i<params.length;i++){
                let param = params[i].trim()
                let paramName = param.split("|")[0]
                let paramType = param.split("|")[1]
                let defaultValue = _getDefaultValueByParamType(paramType)//字符串：'',数字：0，map：{}，其他（新意实体类）：{name：null,age:null}
                obj[paramName]=defaultValue
            }
            target.params = obj
        }
        return JSON.stringify(target).replace(/\"/g,'\\"')
        function _getDefaultValueByParamType(paramType) {
            if (paramType == "java.lang.String") {
                return ""
            } else if (paramType == "java.lang.Integer") {
                return 0
            } else if (paramType == "java.util.Map") {
                return {}
            } else if (paramType == "java.util.List") {
                return []
            } else if (paramType?.startsWith('com.')) {//"so_ba_item_storeDTO|com.shine.dfa.sowp.base.dto.itemmap.So_ba_item_storeDTO"
                return {}
            } else {
                return {}
            }
        }
    }
}

const getArrayJsonFromExcel = (filename,others)=>{
    let sheets = xlsx.parse('./'+filename);//获取到所有sheets
    let arrAllData = {};
    sheets.forEach((sheet)=>{//遍历sheet
        let firstline = sheet.data?.[0]//拿到第一行,作为数组的每一项的key
        let sheetData = []
        sheet.data.forEach((row,rowIndex)=>{
            if(rowIndex>0){
                let rowData={}
                firstline.forEach((title,titleIndex)=>{
                    rowData[title] = row[titleIndex]||''
                })
                sheetData.push(rowData)
            }
        })
        arrAllData[sheet.name] = sheetData
    });

    //写入文件路径 如果有这个文件 会添加 如果没有这个文件会先创建
    fs.writeFile(`${filename}-导出json${getDateTimeString()}.json`, JSON.stringify(arrAllData), function (err) {
        if (err) {
           // console.log(err);
        }
    });
    
}
const getArrayJsonFromCsv = async(filename,others)=>{
    const content = await fs.promises.readFile(filename,{encoding: 'utf8'})
    console.log(content)
    const arrAllData = await csvtojson().fromString(content);
    //写入文件路径 如果有这个文件 会添加 如果没有这个文件会先创建
    fs.writeFile(`${filename}-导出json${getDateTimeString()}.json`, JSON.stringify(arrAllData), function (err) {
        if (err) {
           // console.log(err);
        }
    });
}
const testServiceCsv = async(filename,others)=>{

    let token = "eyJhbGciOiJIUzI1NiJ9.eyJxcHMiOjEwMCwiY2xpZW50IjoidGVzdDYiLCJleHAiOjE3MTQ0NzIyNTB9.GHxwlLPP2m1n1PGF8Ia1T_AGj7Doy2ctKZbqKehd50U"
    let baseUrl = 'http://10.29.197.176/api/'
    console.log("正在测试中，请稍后...")
    const content = await fs.promises.readFile(filename,{encoding: 'utf8'})
    const allServiceDef = await csvtojson().fromString(content);
    const promises = allServiceDef.map(item=> {
        let requestBody = _getRequestBodyStr(item)
        item['请求体'] = JSON.stringify(requestBody)
        return axios.post(baseUrl+item['服务方法'], requestBody,{headers: {'Authorization': token}})
    })  
    Promise.all(promises).then(res=>{
        res.forEach((item,index)=>{
            console.log(item.data)
            allServiceDef[index]['完整响应结果'] = item.data
            allServiceDef[index]['响应结果-rep_header-rep_code'] = item?.data?.rep_header?.rep_code
            allServiceDef[index]['响应结果-rep_header-rep_message'] = item?.data?.rep_header?.rep_message
            allServiceDef[index]['响应结果-data'] = item?.data?.data
            allServiceDef[index]['响应结果-records_total'] = item?.data?.records_total
        })
    }).then(_=>{
        arr2Excel(allServiceDef)
        console.log("测试完成")
    })

    function _getRequestBodyStr(serviceDef){
        let target= {params:{}}
        let serviceParams = serviceDef.serviceParams//userCode|java.lang.String; appName|java.lang.String; resourceType|java.lang.String
    
        let obj = {}
        if(serviceParams&&serviceParams!='无'){
            let params = serviceParams.split(";")
            console.log(params)
            let paramStr = ""
            for(let i=0;i<params.length;i++){
                let param = params[i].trim()
                let paramName = param.split("|")[0]
                let paramType = param.split("|")[1]
                let defaultValue = _getDefaultValueByParamType(paramType)//字符串：'',数字：0，map：{}，其他（新意实体类）：{name：null,age:null}
                obj[paramName]=defaultValue
            }
            target.params = obj
        }
        return target
        function _getDefaultValueByParamType(paramType) {
            if (paramType == "java.lang.String") {
                return "1"
            } else if (paramType == "java.lang.Integer") {
                return 20230301
            } else if (paramType == "java.util.Map") {
                return {}
            } else if (paramType == "java.util.List") {
                return ["1"]
            } else if (paramType?.startsWith('com.')) {//"so_ba_item_storeDTO|com.shine.dfa.sowp.base.dto.itemmap.So_ba_item_storeDTO"
                return {}
            } else {
                return {}
            }
        }
    }  
    //4.生成一个文件存储这个json
    //wiriteToFile(`${filename.substring(0,filename.lastIndexOf('.'))}-apifox.json`,apifoxData)
    //以下是该方法用到的子方法
        
    
}
module.exports = {
    createProjectAction,addPageAndRouterAction,setPlatFormPathAction,serviceDefToApifoxJson,getArrayJsonFromExcel,getArrayJsonFromCsv,testServiceCsv
};